Skip to content

fix(desktop): reopen a chat on the browser tab the user left it on - #7793

Open
waleedlatif1 wants to merge 6 commits into
stagingfrom
fix/browser-tab-restore-on-chat-switch
Open

fix(desktop): reopen a chat on the browser tab the user left it on#7793
waleedlatif1 wants to merge 6 commits into
stagingfrom
fix/browser-tab-restore-on-chat-switch

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Sep 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Reopening a chat landed on the last browser tab instead of the one the user left it on. The resource strip treated its own last-tab fallback as a selection and pushed it to the desktop app, overriding the tab the desktop remembers per chat (which also survives relaunch).
  • The shared desktop-tab hook now switches the native tab only for an explicit selection. With no explicit selection it adopts the desktop app's active tab instead, passively, so agent activity can still take the view the way it does on any chat open.
  • A first report of the desktop app's active tab is the remembered tab arriving, not a switch the user made, so it is adopted rather than claimed. A move away from a tab the desktop app was already showing stays the user's own.
  • A tab selected before the desktop app published its tab list is now shown when the tab arrives instead of being dropped.
  • Closing the shown tab selects its neighbour, right then left, matching how the desktop app picks the next native tab, so the strip no longer flashes through its last tab. Adoption also skips a tab the strip has already dropped, so closing the shown tab cannot write the closed id back.
  • Chat hydration no longer writes a browser or terminal tab into the URL as a fallback; it still pins the last server-held resource.

Note for reviewers

Adoption is gated on hydrated (resolvedChatId === undefined || !isChatHistoryPending) because adopting writes the tab into activeResourceId, the single place the surface reads as the shown resource. Without the gate, whichever of the tab list and the chat history arrived first would decide what the chat opens on. The gate is computed by the caller, so if chat hydration ever moves into a query select, this is the flag to revisit.

Type of Change

  • Bug fix

Testing

  • 199 tests in the two hook suites, including reopen adoption, stale and explicit selections, the hydration gate, liveness on close, first report vs later switch, and late tab arrival. Every new test was checked to fail against the pre-fix code, and both explicit-selection guards plus the liveness narrowing were mutation-tested in each direction.
  • Full apps/sim suite green: 3,543 files, 50,870 tests. bun run type-check across all workspaces, bun run lint, bun run check:audits (46 audits), check:migrations, and docs-manifest:check all pass.
  • Verified in the real desktop app against a local build: opened three pages in a chat, left it on the middle one, switched to another chat and back, and the strip returned to the middle page with the desktop app's active tab matching.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

🤖 Generated with Claude Code

https://claude.ai/code/session_0139YonWmiZUnPMTHoH4PtAJ

The resource strip pushed its own last-tab fallback onto the desktop app
whenever a chat opened without an explicit selection, overriding the tab
the desktop remembers the user was on. The shared desktop-tab hook now
switches the native tab only for an explicit selection, adopts the
desktop's active tab when the strip is on its fallback, and defers a
selected tab that has not landed yet until it does. Chat hydration no
longer writes a browser or terminal tab into the URL as a fallback.
@vercel

vercel Bot commented Sep 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
docs Skipped Skipped Sep 12, 2026 4:53pm UTC

Request Review

@greptile-apps

greptile-apps Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

The PR appears safe to merge with no outstanding correctness, security, or repository-rule issues identified.

Summary

  • Distinguishes explicit resource selections from passive fallback state.
  • Adopts the desktop application's remembered active tab after chat hydration without claiming user ownership.
  • Preserves explicit selections made before native tabs become available.
  • Selects the matching neighboring resource when the visible tab closes.
  • Avoids persisting browser or terminal fallback tabs during chat hydration.
  • Adds browser and terminal hook coverage for restoration, hydration ordering, native switches, tab closure, and late tab arrival.
  • Updates test hosts to use the exported DesktopTabStripOptions interface, resolving the previous component-props rule violation.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Chat opens] --> B[Apply stored chat resources]
    B --> C{Explicit resource selected?}
    C -->|Yes| D{Selected native tab live?}
    D -->|Yes| E[Switch desktop to selected tab]
    D -->|No| F[Wait for tab list]
    F --> E
    C -->|No| G{Chat hydrated?}
    G -->|No| H[Wait for hydration]
    H --> G
    G -->|Yes| I[Read desktop active tab]
    I --> J{Tab still represented in strip?}
    J -->|Yes| K[Passively restore shown resource]
    J -->|No| L[Keep current fallback]
    K --> M[Agent activity may still take view]
Loading

Reviews (5) · Last reviewed commit: "test(desktop): give the tab-resource hos..."

Comment thread apps/sim/app/workspace/[workspaceId]/home/hooks/use-desktop-tab-resources.ts Outdated
…lection

Review round on the reopen fix.

A late first report of the desktop app's active tab carries the tab it
remembers, not a switch the user made, so it is adopted rather than
claimed and agent activity can still take the view on chat open. A move
away from a tab the desktop was already showing stays the user's own.

Adoption now waits for the chat history to be applied, so the arrival
order of the tab list and the history no longer decides which resource a
chat opens on, and it skips a tab the strip has already dropped, so
closing the shown tab cannot write the closed id back. Closing the shown
tab selects its neighbour the way the desktop app picks the next native
tab, instead of flashing through the strip's last tab.

The two wrapper hooks now share one options type with the strip, and the
adopt rule lives in a single helper.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0139YonWmiZUnPMTHoH4PtAJ
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

Comment thread apps/sim/app/workspace/[workspaceId]/home/hooks/use-desktop-tab-resources.ts Outdated
The effect that shows an explicitly selected tab was keyed on the
selection alone, so a selection made before the desktop app published
its tab list was dropped rather than applied when the tab arrived. It is
now keyed on that tab being live as well, which covers the late arrival
without a retry ref to arm and disarm.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0139YonWmiZUnPMTHoH4PtAJ
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

waleedlatif1 and others added 2 commits September 12, 2026 09:36
…mbing

Quality pass on the reopen fix.

The late-arrival adoption now carries the same guards as the hydrated
one, so a first report of the desktop app's active tab can no longer
override a selection the user made before the tab list arrived. Both
guards are pinned by tests that fail when either is removed.

The predicate the adopt and claim paths share moved into one helper, so
the single difference between them — adoption needs the tab to still be
in the strip, following the user does not — is stated once. Removes a
ref nothing read and an options interface with no second consumer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0139YonWmiZUnPMTHoH4PtAJ
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

The test hosts took their props through a type alias derived from the
hook signature. The repo asks for an interface, and the hook already
exports one that is exactly this shape, so the hosts use it directly
instead of restating it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0139YonWmiZUnPMTHoH4PtAJ
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant